From d0e7d6f6d6ff4d599b55b27f7c066f6c7d8f578f Mon Sep 17 00:00:00 2001
From: Alexey Gladkov <legion@altlinux.org>
Date: Wed, 4 Aug 2021 10:07:16 +0200
Subject: Implement losetup as builtin

Signed-off-by: Alexey Gladkov <legion@altlinux.org>
---
 src/Makefile.am     |  2 +-
 src/bltin/losetup.c | 87 +++++++++++++++++++++++++++++++++++++++++++++
 src/builtins.def.in |  1 +
 3 files changed, 89 insertions(+), 1 deletion(-)
 create mode 100644 src/bltin/losetup.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 1732465..85e1098 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,7 +20,7 @@ dash_CFILES = \
 	alias.c arith_yacc.c arith_yylex.c cd.c error.c eval.c exec.c expand.c \
 	histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
 	mystring.c options.c parser.c redir.c show.c trap.c output.c \
-	bltin/printf.c system.c bltin/test.c bltin/times.c var.c
+	bltin/printf.c system.c bltin/test.c bltin/times.c bltin/losetup.c var.c
 dash_SOURCES = \
 	$(dash_CFILES) \
 	alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
diff --git a/src/bltin/losetup.c b/src/bltin/losetup.c
new file mode 100644
index 0000000..84d4a70
--- /dev/null
+++ b/src/bltin/losetup.c
@@ -0,0 +1,87 @@
+/*
+ * Losetup command.
+ */
+
+#define main losetupcmd
+
+#ifdef USE_GLIBC_STDIO
+#include <stdio.h>
+
+#include "../mystring.h"
+#else
+#include "bltin.h"
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#ifndef	dev_t
+#define	dev_t	dev_t
+#endif
+#include <linux/loop.h>
+
+int
+main(int argc, const char *const *argv)
+{
+	int loopfd, targfd;
+	struct loop_info loopInfo;
+
+	if ( argc < 3 )
+		return 1;
+
+	if ( !strcmp( argv[1], "-d" ) )
+	{
+		loopfd = open( argv[2], O_RDONLY );
+		if ( loopfd < 0 )
+		{
+			fprintf( stderr, "losetup: error opening %s: %s\n", argv[2], strerror(errno) );
+			return 1;
+		}
+
+		if ( ioctl(loopfd, LOOP_CLR_FD, 0) < 0 )
+		{
+			fprintf( stderr, "losetup: error unassociating device: %s\n", strerror(errno) );
+			close( loopfd );
+			return 1;
+		}
+
+		close( loopfd );
+		return 0;
+	}
+
+	loopfd = open( argv[1], O_RDONLY );
+	if ( loopfd < 0 )
+	{
+		fprintf( stderr, "losetup: error opening %s: %s\n", argv[1], strerror(errno) );
+		return 1;
+	}
+
+	targfd = open( argv[2], O_RDONLY );
+	if ( targfd < 0 )
+	{
+		fprintf( stderr, "losetup: error opening %s: %s\n", argv[2], strerror(errno) );
+		close( loopfd );
+		return 1;
+	}
+
+	if ( ioctl(loopfd, LOOP_SET_FD, targfd) < 0 )
+	{
+		fprintf( stderr, "losetup: error setting up loopback device: %s\n", strerror(errno) );
+		close( loopfd );
+		close( targfd );
+		return 1;
+	}
+
+	memset(&loopInfo, 0, sizeof(loopInfo));
+	strcpy(loopInfo.lo_name, argv[2]);
+
+	if ( ioctl(loopfd, LOOP_SET_STATUS, &loopInfo) < 0 )
+		fprintf( stderr, "losetup: error setting up loopback device: %s\n", strerror(errno) );
+
+	close( loopfd );
+	close( targfd );
+
+	return 0;
+}
diff --git a/src/builtins.def.in b/src/builtins.def.in
index 95e420c..87f0476 100644
--- a/src/builtins.def.in
+++ b/src/builtins.def.in
@@ -92,3 +92,4 @@ ulimitcmd	-u ulimit
 #endif
 testcmd		test [
 killcmd		-u kill
+losetupcmd	losetup
-- 
2.29.3

